package org.example.spring;

import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;

public class MyApplicationContext {
    
    public Class<?> configClass;
    private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap= new ConcurrentHashMap<String,BeanDefinition>();
    private ConcurrentHashMap<String,Object> singletonObjects=new ConcurrentHashMap<String,Object>();

    public MyApplicationContext(Class<?> configClass)  {
        this.configClass = configClass;
        //扫描
        if(configClass.isAnnotationPresent(ComponentScan.class)){
            ComponentScan componentScan = configClass.getAnnotation(ComponentScan.class);
            String path=componentScan.value();
            System.out.println(path);
            path=path.replace(".","/");
            ClassLoader classLoader=configClass.getClassLoader();
            URL resource=classLoader.getResource(path);
            
            File file=new File(resource.getFile());
            System.out.println(file);
            if (file.isDirectory()){
                File[] files=file.listFiles();
                for (File f : files){
                    String fileName=f.getAbsolutePath();
                    if(fileName.endsWith(".class")){
                        String className=path.replace("/",".")+"."+fileName.substring(fileName.lastIndexOf("\\")+1, fileName.length()-6);
                        System.out.println(className);
                        Class<?> clazz;
                        try {
                            clazz = classLoader.loadClass(className);
                            if(clazz.isAnnotationPresent(Component.class)){
                                Component component=clazz.getAnnotation(Component.class);
                                String beanName=component.value();
                                if(beanName.equals("")){
                                    beanName=Introspector.decapitalize(clazz.getSimpleName());
                                }
                                //Bean
                                BeanDefinition beanDefinition =new BeanDefinition();
                                beanDefinition.setType(clazz);
                                if(clazz.isAnnotationPresent(Scope.class)){
                                    Scope annotationScope = clazz.getAnnotation(Scope.class);
                                    beanDefinition.setScope(annotationScope.value());
                                }else{
                                    beanDefinition.setScope("singleton");
                                }
                                beanDefinitionMap.put(beanName, beanDefinition);
                            }
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }
                       
                    }
                }
            }
        }
        //创建单例bean
        for(String beanName:beanDefinitionMap.keySet()){
            BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
            if(beanDefinition.getScope().equals("singleton")){
                Object bean=createBean(beanName,beanDefinition);
                singletonObjects.put(beanName, bean);
            }
        }
    }

    private Object createBean(String beanName, BeanDefinition beanDefinition) {
        Class<?> clazz = beanDefinition.getType();
        try {
            Object instance=clazz.getConstructor().newInstance();
            for(Field field : clazz.getDeclaredFields()){
                //依赖注入
                if(field.isAnnotationPresent(Autowired.class)){
                    field.setAccessible(true);
                    field.set(instance,getBean(field.getName()));
                }
            }
            if (instance instanceof BeanNameAware){
                ((BeanNameAware) instance).setBeanName(beanName);
            }
            if (instance instanceof InitiallizingBean){
                ((InitiallizingBean) instance).afterPropertiesSet();
            }
            return instance;
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
                | NoSuchMethodException | SecurityException e) {
            e.printStackTrace();
        }
        return null;
    }

    public Object getBean(String beanName) {
        System.out.println("beanName:"+beanName);
        BeanDefinition beanDefinition=beanDefinitionMap.get(beanName);
        if (beanDefinition==null){
            throw new NullPointerException();
        }else{
            String scope =beanDefinition.getScope();
            if(scope.equals("singleton")){
                Object bean=singletonObjects.get(beanName);
                if (bean==null){
                    bean=createBean(beanName, beanDefinition);
                    singletonObjects.put(beanName, bean);
                }
                return bean;
            }else{
               Object bean=createBean(beanName, beanDefinition);
               return bean;
            }
        }
    }
}